home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / mail / mh / vmail / vmail.2of3 < prev    next >
Encoding:
Text File  |  1991-04-05  |  57.3 KB  |  2,111 lines

  1. (Message mh:7)
  2. Resent: Mon, 25 Mar 91 10:19:03 PST
  3. Resent: qq11@uxb.liv.ac.uk (Alan Thew)
  4. Resent: Mon, 18 Mar 91 12:22:10 PST
  5. Resent: jcohn@nsf.gov (Johnathan Charles Cohn)
  6. Resent: rjg@sq.com (Bob Gibson)
  7. Resent: dak@sq.com (David Keldson)
  8. Resent: sow@cad.luth.se (Sven-Ove Westberg)
  9. Resent: cenkl@linus.mitre.org (Mike Cenkl)
  10. Resent: david@scocan.sco.com (David J Fiander)
  11. Return-Path: jamesp@metolius.WR
  12. To: luj@ecn.purdue.edu (Jun Lu), jkm@ctt.bellcore.COM (James Mcglashan),
  13.         jmvogtle@gamera.cns.syr.edu (John M Vogtle),
  14.         cks@hawkwind.utcs.toronto.edu (Chris Siebenmann),
  15.         ccw@deakin.OZ.AU (Craig Warren), rr@mips.COM (Robert "Bob" Rodriguez),
  16.         munck@Stars.Reston.Unisys.COM (Bob Munck)
  17. Cc: jamesp@metolius.WR.TEK.COM (James Perkins)
  18. Subject: Vmail - version 10/87DAS - part 2/3
  19. Reply-To: jamesp@metolius.WR.TEK.COM (James T. Perkins)
  20. Reply-To: traveller-request@metolius.WR.TEK.COM (TML Administrator)
  21. X-Mailer: Rand MH 6.6 - Vmail 10/87DAS - Vmailtool V1.14 91/02/27
  22. Date: Mon, 11 Mar 91 11:43:48 PST
  23. From: James T Perkins <jamesp@metolius.WR>
  24. --------
  25.  
  26.  
  27. #! /bin/sh
  28. # This is a shell archive.  Remove anything before this line, then unpack
  29. # it by saving it into a file and typing "sh file".  To overwrite existing
  30. # files, type "sh file -c".  You can also feed this as standard input via
  31. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  32. # will see the following message at the end:
  33. #        "End of archive 2 (of 3)."
  34. # Contents:  call.c init.c main.c move.c vmail.1
  35. # Wrapped by jamesp@metolius on Mon Mar 11 11:20:04 1991
  36. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  37. if test -f call.c -a "${1}" != "-c" ; then 
  38.   echo shar: Will not over-write existing file \"call.c\"
  39. else
  40. echo shar: Extracting \"call.c\" \(10995 characters\)
  41. sed "s/^X//" >call.c <<'END_OF_call.c'
  42. X#ifndef lint
  43. Xstatic char *RCS_call_c = "$Id: call.c,v 1.5 90/09/19 13:53:33 rogers Exp $";
  44. X#endif
  45. X
  46. X/* --------------------
  47. X    vmail -- call.c
  48. X
  49. X    Routines that call MH equivalents, editor, shell.
  50. X
  51. X    Copyright (C) J. Zobel, University of Melbourne, October 1987.
  52. X-------------------- */
  53. X
  54. X#include "defs.h"
  55. X#include <signal.h>
  56. X
  57. X#define WARNING    "Warning -- mail headers may be out of date"
  58. X
  59. Xunion wait status;
  60. X
  61. X/* --------------------
  62. X    Fork a call to `comp'.
  63. X    Terminal type must be reset before call.
  64. X-------------------- */
  65. Xvoid
  66. Xcomp()
  67. X{
  68. X    char    *tmp, *argv[20], str[LEN], s1[LEN], *next_token();
  69. X    int        i;
  70. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  71. X
  72. X    *s1 = '\0';
  73. X    if(comp_args) {
  74. X        (void)sprintf(str, "(give options to)   comp ");
  75. X        get_string(str, s1);
  76. X    }
  77. X    clear();
  78. X    addstatus("composing mail ...", false);
  79. X    move(STATUS+1, 0);
  80. X    refresh();
  81. X    top_level = false;            /* used by tstp() so that right thing is done
  82. X                                   when process is restarted */
  83. X    if(! vfork()) {
  84. X        argv[0] = COMP;
  85. X        for(i=1, tmp=s1 ; *tmp != '\0' ; i++) {
  86. X            argv[i] = tmp;
  87. X            tmp = next_token(tmp);
  88. X        }
  89. X        argv[i] = 0;
  90. X        no_control();
  91. X        execvp(COMP, argv);
  92. X        (void)printf("Warning: can't execute %s\n", COMP);
  93. X        exit(0);
  94. X    }
  95. X    oldint = signal(SIGINT, SIG_IGN);
  96. X    oldquit = signal(SIGQUIT, SIG_IGN);
  97. X    (void)wait(&status);
  98. X    (void)signal(SIGINT, oldint);
  99. X    (void)signal(SIGQUIT, oldquit);
  100. X    top_level = true;
  101. X    to_control();
  102. X    hold_end();                    /* wait for user to want to continue - may wish
  103. X                                   to read error messages */
  104. X    display_page();
  105. X    addstatus(WARNING, true);    /* vmail's data structures not updated */
  106. X}
  107. X
  108. X
  109. X/* --------------------
  110. X    Fork a call to `forw'.
  111. X    Terminal type must be reset before call.
  112. X-------------------- */
  113. Xvoid
  114. Xforw()
  115. X{
  116. X    char    *tmp, *argv[20], str[LEN], s1[LEN], s2[10], *next_token();
  117. X    int        i;
  118. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  119. X
  120. X    (void)sprintf(s2, "%d", curmail->number);
  121. X    *s1 = '\0';
  122. X    if(forw_args) {
  123. X        (void)sprintf(str, "(give options to)   forw +%s %s ", curflr->name, s2);
  124. X        get_string(str, s1);
  125. X    }
  126. X    clear();
  127. X    addstatus("forwarding mail ...", false);
  128. X    move(STATUS+1, 0);
  129. X    refresh();
  130. X    top_level = false;            /* used by tstp() so that right thing is done
  131. X                                   when process is restarted */
  132. X    if(! vfork()) {
  133. X        (void)sprintf(str, "+%s", curflr->name);
  134. X        argv[0] = FORW; argv[1] = str; argv[2] = s2;
  135. X        for(i=3, tmp=s1 ; *tmp != '\0' ; i++) {
  136. X            argv[i] = tmp;
  137. X            tmp = next_token(tmp);
  138. X        }
  139. X        argv[i] = 0;
  140. X        no_control();
  141. X        execvp(FORW, argv);
  142. X        (void)printf("Warning: can't execute %s\n", FORW);
  143. X        exit(0);
  144. X    }
  145. X    oldint = signal(SIGINT, SIG_IGN);
  146. X    oldquit = signal(SIGQUIT, SIG_IGN);
  147. X    (void)wait(&status);
  148. X    (void)signal(SIGINT, oldint);
  149. X    (void)signal(SIGQUIT, oldquit);
  150. X    top_level = true;
  151. X    to_control();
  152. X    hold_end();                    /* wait for user to want to continue - may wish
  153. X                                   to read error messages */
  154. X    display_page();
  155. X    addstatus(WARNING, true);    /* vmail's data structures not updated */
  156. X}
  157. X
  158. X
  159. X/* --------------------
  160. X    Fork a call to `repl'.
  161. X    Terminal type must be reset before call.
  162. X-------------------- */
  163. Xvoid
  164. Xrepl()
  165. X{
  166. X    char    *tmp, *argv[20], str[LEN], s1[LEN], s2[10], *next_token();
  167. X    int        i;
  168. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  169. X
  170. X    (void)sprintf(s2, "%d", curmail->number);
  171. X    *s1 = '\0';
  172. X    if(repl_args) {
  173. X        (void)sprintf(str, "(give options to)   repl +%s %s ", curflr->name, s2);
  174. X        get_string(str, s1);
  175. X    }
  176. X    clear();
  177. X    addstatus("answering mail ...", false);
  178. X    move(STATUS+1, 0);
  179. X    refresh();
  180. X    top_level = false;            /* used by tstp() so that right thing is done
  181. X                                   when process is restarted */
  182. X    if(! vfork()) {
  183. X        (void)sprintf(str, "+%s", curflr->name);
  184. X        argv[0] = REPL; argv[1] = str; argv[2] = s2;
  185. X        for(i=3, tmp=s1 ; *tmp != '\0' ; i++) {
  186. X            argv[i] = tmp;
  187. X            tmp = next_token(tmp);
  188. X        }
  189. X        argv[i] = 0;
  190. X        no_control();
  191. X        execvp(REPL, argv);
  192. X        (void)printf("Warning: can't execute %s\n", REPL);
  193. X        exit(0);
  194. X    }
  195. X    oldint = signal(SIGINT, SIG_IGN);
  196. X    oldquit = signal(SIGQUIT, SIG_IGN);
  197. X    (void)wait(&status);
  198. X    (void)signal(SIGINT, oldint);
  199. X    (void)signal(SIGQUIT, oldquit);
  200. X    top_level = true;
  201. X    to_control();
  202. X    hold_end();                    /* wait for user to want to continue - may wish
  203. X                                   to read error messages */
  204. X    display_page();
  205. X    addstatus(WARNING, true);    /* vmail's data structures not updated */
  206. X}
  207. X
  208. X
  209. X/* --------------------
  210. X    Fork a call to editor.
  211. X    Terminal type must be reset before call.
  212. X-------------------- */
  213. Xvoid
  214. Xedit()
  215. X{
  216. X    char    str[LEN];
  217. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  218. X
  219. X    clear();
  220. X    mvaddstr(TITLE, 0, "editing mail ...");
  221. X    move(STATUS, 0);
  222. X    refresh();
  223. X    top_level = false;            /* used by tstp() so that right thing is done
  224. X                                   when process is restarted */
  225. X    if(! vfork()) {
  226. X        no_control();
  227. X        (void)sprintf(str, "%s/%s/%d", mail_dir, curflr->name, curmail->number);
  228. X        execlp(editor, editor, str, 0);
  229. X        (void)printf("Warning: can't execute %s\n", editor);
  230. X        exit(0);
  231. X    }
  232. X    oldint = signal(SIGINT, SIG_IGN);
  233. X    oldquit = signal(SIGQUIT, SIG_IGN);
  234. X    (void)wait(&status);
  235. X    (void)signal(SIGINT, oldint);
  236. X    (void)signal(SIGQUIT, oldquit);
  237. X    top_level = true;
  238. X    to_control();
  239. X    hold_end();                    /* wait for user to want to continue - may wish
  240. X                                   to read error messages */
  241. X    display_page();
  242. X    addstatus(WARNING, true);    /* vmail's data structures not updated */
  243. X}
  244. X
  245. X
  246. X/* --------------------
  247. X    Fork a call to shell.
  248. X    Terminal type must be reset before call.
  249. X
  250. X    This should perhaps be modified so that only a single command can be
  251. X    issued, as in vi ... but this was simpler to do.
  252. X-------------------- */
  253. Xvoid
  254. Xcall_shell()
  255. X{
  256. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  257. X
  258. X    clear();
  259. X    mvaddstr(TITLE, 0, "calling shell ...");
  260. X    move(STATUS, 0);
  261. X    refresh();
  262. X    top_level = false;            /* used by tstp() so that right thing is done
  263. X                                   when process is restarted */
  264. X    if(! vfork()) {
  265. X        no_control();
  266. X        fix_mh();
  267. X        execlp(shell, shell, "-i", 0);
  268. X        (void)printf("Warning: can't execute %s\n", shell);
  269. X        exit(0);
  270. X    }
  271. X    oldint = signal(SIGINT, SIG_IGN);
  272. X    oldquit = signal(SIGQUIT, SIG_IGN);
  273. X    (void)wait(&status);
  274. X    (void)signal(SIGINT, oldint);
  275. X    (void)signal(SIGQUIT, oldquit);
  276. X    top_level = true;
  277. X    to_control();
  278. X    hold_end();                    /* wait for user to want to continue - may wish
  279. X                                   to read error messages */
  280. X    display_page();
  281. X}
  282. X
  283. X
  284. X/* --------------------
  285. X    Pipe current mail item into given command.
  286. X-------------------- */
  287. Xvoid
  288. Xdo_pipe()
  289. X{
  290. X    char    str[LEN], s1[LEN];
  291. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  292. X
  293. X    *s1 = '\0';
  294. X    (void)sprintf(str, "(give command to)   show +%s %d | ", curflr->name,
  295. X                                                        curmail->number);
  296. X    get_string(str, s1);
  297. X    clear();
  298. X    addstatus("piping mail ...", false);
  299. X    move(STATUS+1, 0);
  300. X    refresh();
  301. X    (void)sprintf(str, "%s %s/%s/%d | %s", CAT, mail_dir, curflr->name,
  302. X                                                        curmail->number, s1);
  303. X    top_level = false;            /* used by tstp() so that right thing is done
  304. X                                   when process is restarted */
  305. X    no_control();
  306. X    oldint = signal(SIGINT, SIG_IGN);
  307. X    oldquit = signal(SIGQUIT, SIG_IGN);
  308. X    (void)system(str);            /* exec needs full path of command => use system */
  309. X    (void)signal(SIGINT, oldint);
  310. X    (void)signal(SIGQUIT, oldquit);
  311. X    top_level = true;
  312. X    to_control();
  313. X    hold_end();                    /* wait for user to want to continue - may wish
  314. X                                   to read error messages */
  315. X    display_page();
  316. X}
  317. X
  318. X/* --------------------
  319. X    Fork a call to `burst'.
  320. X    Terminal type must be reset before call.
  321. X-------------------- */
  322. Xvoid
  323. Xburst_item()
  324. X{
  325. X    char    *tmp, *argv[20], str[LEN], s1[LEN], s2[10], *next_token();
  326. X    int        i;
  327. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  328. X
  329. X    (void)sprintf(s2, "%d", curmail->number);
  330. X    *s1 = '\0';
  331. X    if(burst_args) {
  332. X        (void)sprintf(str, "(give options to)  burst +%s %s ", curflr->name, s2);
  333. X        get_string(str, s1);
  334. X    }
  335. X    clear();
  336. X    addstatus("bursting mail ...", false);
  337. X    move(STATUS+1, 0);
  338. X    refresh();
  339. X    top_level = false;            /* used by tstp() so that right thing is done
  340. X                                   when process is restarted */
  341. X    if(! vfork()) {
  342. X        (void)sprintf(str, "+%s", curflr->name);
  343. X        argv[0] = BURST; argv[1] = str; argv[2] = s2;
  344. X        for(i=3, tmp=s1 ; *tmp != '\0' ; i++) {
  345. X            argv[i] = tmp;
  346. X            tmp = next_token(tmp);
  347. X        }
  348. X        argv[i] = 0;
  349. X        no_control();
  350. X        execvp(BURST, argv);
  351. X        (void)printf("Warning: can't execute %s\n", BURST);
  352. X        exit(0);
  353. X    }
  354. X    oldint = signal(SIGINT, SIG_IGN);
  355. X    oldquit = signal(SIGQUIT, SIG_IGN);
  356. X    (void)wait(&status);
  357. X    (void)signal(SIGINT, oldint);
  358. X    (void)signal(SIGQUIT, oldquit);
  359. X    top_level = true;
  360. X    to_control();
  361. X    hold_end();                    /* wait for user to want to continue - may wish
  362. X                                   to read error messages */
  363. X    clear();
  364. X    move(STATUS, 0);
  365. X    refresh_folder();
  366. X}
  367. X
  368. X/* --------------------
  369. X    Fork a call to `dist'.
  370. X    Terminal type must be reset before call.
  371. X-------------------- */
  372. Xvoid
  373. Xdist_item()
  374. X{
  375. X    char    *tmp, *argv[20], str[LEN], s1[LEN], s2[10], *next_token();
  376. X    int        i;
  377. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  378. X
  379. X    (void)sprintf(s2, "%d", curmail->number);
  380. X    *s1 = '\0';
  381. X    if(dist_args) {
  382. X        (void)sprintf(str, "(give options to)   dist +%s %s ", curflr->name, s2);
  383. X        get_string(str, s1);
  384. X    }
  385. X    clear();
  386. X    addstatus("disting mail ...", false);
  387. X    move(STATUS+1, 0);
  388. X    refresh();
  389. X    top_level = false;            /* used by tstp() so that right thing is done
  390. X                                   when process is restarted */
  391. X    if(! vfork()) {
  392. X        (void)sprintf(str, "+%s", curflr->name);
  393. X        argv[0] = DIST; argv[1] = str; argv[2] = s2;
  394. X        for(i=3, tmp=s1 ; *tmp != '\0' ; i++) {
  395. X            argv[i] = tmp;
  396. X            tmp = next_token(tmp);
  397. X        }
  398. X        argv[i] = 0;
  399. X        no_control();
  400. X        execvp(DIST, argv);
  401. X        (void)printf("Warning: can't execute %s\n", DIST);
  402. X        exit(0);
  403. X    }
  404. X    oldint = signal(SIGINT, SIG_IGN);
  405. X    oldquit = signal(SIGQUIT, SIG_IGN);
  406. X    (void)wait(&status);
  407. X    (void)signal(SIGINT, oldint);
  408. X    (void)signal(SIGQUIT, oldquit);
  409. X    top_level = true;
  410. X    to_control();
  411. X    hold_end();                    /* wait for user to want to continue - may wish
  412. X                                   to read error messages */
  413. X    display_page();
  414. X    addstatus(WARNING, true);    /* vmail's data structures not updated */
  415. X}
  416. X
  417. X/* --------------------
  418. X    Fork a call to `sortm'.
  419. X    Terminal type must be reset before call.
  420. X-------------------- */
  421. Xvoid
  422. Xsort_folder()
  423. X{
  424. X    char    *tmp, *argv[20], str[LEN], s1[LEN], *next_token();
  425. X    int        i;
  426. X    sig_type    (*oldint)(), (*oldquit)(), (*signal())();
  427. X
  428. X    *s1 = '\0';
  429. X    if(sort_args) {
  430. X        (void)sprintf(str, "(give options to)  sortm +%s ", curflr->name);
  431. X        get_string(str, s1);
  432. X    }
  433. X    clear();
  434. X    addstatus("sorting mail ...", false);
  435. X    move(STATUS+1, 0);
  436. X    refresh();
  437. X    top_level = false;            /* used by tstp() so that right thing is done
  438. X                                   when process is restarted */
  439. X    if(! vfork()) {
  440. X        (void)sprintf(str, "+%s", curflr->name);
  441. X        argv[0] = SORTM; argv[1] = str;
  442. X        for(i=2, tmp=s1 ; *tmp != '\0' ; i++) {
  443. X            argv[i] = tmp;
  444. X            tmp = next_token(tmp);
  445. X        }
  446. X        argv[i] = 0;
  447. X        no_control();
  448. X        execvp(SORTM, argv);
  449. X        (void)printf("Warning: can't execute %s\n", SORTM);
  450. X        exit(0);
  451. X    }
  452. X    oldint = signal(SIGINT, SIG_IGN);
  453. X    oldquit = signal(SIGQUIT, SIG_IGN);
  454. X    (void)wait(&status);
  455. X    (void)signal(SIGINT, oldint);
  456. X    (void)signal(SIGQUIT, oldquit);
  457. X    top_level = true;
  458. X    to_control();
  459. X    hold_end();                    /* wait for user to want to continue - may wish
  460. X                                   to read error messages */
  461. X    clear();
  462. X    move(STATUS, 0);
  463. X    refresh_folder();
  464. X}
  465. END_OF_call.c
  466. if test 10995 -ne `wc -c <call.c`; then
  467.     echo shar: \"call.c\" unpacked with wrong size!
  468. fi
  469. # end of overwriting check
  470. fi
  471. if test -f init.c -a "${1}" != "-c" ; then 
  472.   echo shar: Will not over-write existing file \"init.c\"
  473. else
  474. echo shar: Extracting \"init.c\" \(11104 characters\)
  475. sed "s/^X//" >init.c <<'END_OF_init.c'
  476. X#ifndef lint
  477. Xstatic char *RCS_init_c = "$Id: init.c,v 1.3 90/04/23 14:41:11 rogers Exp $";
  478. X#endif
  479. X
  480. X/* --------------------
  481. X    vmail -- init.c
  482. X
  483. X    Initialisation routines - setting ttystate, finding valid folders,
  484. X    trapping signals.
  485. X
  486. X    Ttystate is controlled by a mix of curses and ioctl.  For simplicity,
  487. X    initial setups are done with curses.  Curses is also used for basic
  488. X    screen manipulation.  However, for speed ioctl is used in switching
  489. X    in and out of normal terminal state.
  490. X
  491. X    Copyright (C) J. Zobel, University of Melbourne, October 1987.
  492. X-------------------- */
  493. X
  494. X#include "defs.h"
  495. X#include <signal.h>
  496. X
  497. Xstatic struct sgttyb tty, t_tty;        /* for holding tty state */
  498. Xstatic struct tchars chrs, t_chrs;
  499. Xstatic struct ltchars lchrs, t_lchrs;
  500. X
  501. Xstatic char    termcap[1024],                /* termcap entry */
  502. X            *cur_folder;                /* initial current folder */
  503. X
  504. Xsig_type    tstp(), tint();
  505. X
  506. X/* --------------------
  507. X    Start-up routine - set terminal control, signals, etc.
  508. X-------------------- */
  509. Xvoid
  510. Xinit(argc, argv)
  511. X    int        argc;
  512. X    char    **argv;
  513. X{
  514. X    folder    ftmp, find_mail();
  515. X    char    *pargv[20],                    /* argv from profile */
  516. X            *profile = (char *) NULL,    /* location of MH profile */
  517. X            *home = (char *) NULL,        /* home directory */
  518. X            *term = (char *) NULL;        /* terminal type */
  519. X    int        pargc = 0;                    /* argc from profile */
  520. X
  521. X    get_home(&home);
  522. X    get_env(&term, &profile, home);
  523. X    (void)tgetent(termcap, term);
  524. X    cols = tgetnum("co");
  525. X        /* lines holds no. of lines for headers, ie "li" less STATUS, TITLE */
  526. X    lines = tgetnum("li") - 2;
  527. X    (void)ioctl(0, TIOCGETP, (caddr_t)&tty);
  528. X    (void)ioctl(0, TIOCGETP, (caddr_t)&chrs);
  529. X    (void)ioctl(0, TIOCGETP, (caddr_t)&lchrs);
  530. X
  531. X    read_profile(&pargc, pargv, profile, home);
  532. X    process_args(pargc, pargv);
  533. X    find_folders();
  534. X    mark_valid_folders(pargc, pargv);
  535. X        /* give precedence to command line args => process second */
  536. X    mark_valid_folders(argc, argv);
  537. X    for(ftmp=folders ; ftmp != (folder) NULL ;)
  538. X        if(ftmp->valid)
  539. X            ftmp = find_mail(ftmp, true);
  540. X        else
  541. X            ftmp = ftmp->next;
  542. X    if(curflr->valid == EMPTY) {
  543. X        (void)printf("%s: folder empty.\n", curflr->name);
  544. X        exit(1);
  545. X    }
  546. X        /* find last instance of initial folder */
  547. X    LAST_OF_NAME(curflr);
  548. X    curmail = curflr->mail;
  549. X
  550. X    (void)initscr();
  551. X    (void)crmode();
  552. X    (void)noecho();
  553. X    (void)nonl();
  554. X
  555. X    (void)signal(SIGTSTP, tstp);
  556. X    (void)signal(SIGINT, tint);
  557. X
  558. X    (void)ioctl(0, TIOCGETP, (caddr_t)&t_tty);
  559. X    (void)ioctl(0, TIOCGETP, (caddr_t)&t_chrs);
  560. X    (void)ioctl(0, TIOCGETP, (caddr_t)&t_lchrs);
  561. X
  562. X    y = FIRST;
  563. X    display_page();
  564. X}
  565. X
  566. X
  567. X/* --------------------
  568. X    Find user name, home directory.
  569. X-------------------- */
  570. Xvoid
  571. Xget_home(home)
  572. X    char **home;
  573. X{
  574. X    struct passwd *pwent, *getpwuid();
  575. X#ifdef vax
  576. X    uid_t getuid();
  577. X#endif
  578. X
  579. X    pwent = getpwuid((int)getuid());
  580. X    *home = NEWSTR(strlen(pwent->pw_dir)+1);
  581. X    (void)strcpy(*home, pwent->pw_dir);
  582. X    if(access(*home, R_OK | W_OK | X_OK)) {
  583. X        (void)printf("%s: no permissions.\n", *home);
  584. X        exit(1);
  585. X    }
  586. X    user = NEWSTR(strlen(pwent->pw_name)+1);
  587. X    (void)strcpy(user, pwent->pw_name);
  588. X}
  589. X
  590. X
  591. X/* --------------------
  592. X    Find pager, editor, shell, terminal type, MH profile - defaults are PAGER,
  593. X    EDITOR, SHELL, none, PROFILE.  Set by PAGER, EDITOR, SHELL, TERM, MH
  594. X    environment variables.
  595. X-------------------- */
  596. Xvoid
  597. Xget_env(term, profile, home)
  598. X    char **term, **profile, *home;
  599. X{
  600. X    char    **tmp;
  601. X
  602. X    for(tmp = environ ; *tmp != (char *) NULL ; tmp++)
  603. X        if(!strncmp("PAGER=", *tmp, 6)) {
  604. X            pager = NEWSTR(strlen(*tmp)-4);
  605. X            (void)strcpy(pager, *tmp+6);
  606. X        } else if(!strncmp("EDITOR=", *tmp, 7)) {
  607. X            editor = NEWSTR(strlen(*tmp)-5);
  608. X            (void)strcpy(editor, *tmp+7);
  609. X        } else if(!strncmp("SHELL=", *tmp, 6)) {
  610. X            shell = NEWSTR(strlen(*tmp)-4);
  611. X            (void)strcpy(shell, *tmp+6);
  612. X        } else if(!strncmp("TERM=", *tmp, 5)) {
  613. X            *term = NEWSTR(strlen(*tmp)-3);
  614. X            (void)strcpy(*term, *tmp+5);
  615. X        } else if(!strncmp("MH=", *tmp, 3)) {
  616. X            *profile = NEWSTR(strlen(*tmp)-1);
  617. X            (void)strcpy(*profile, *tmp+3);
  618. X        }
  619. X    if(*term == (char *) NULL) {
  620. X        (void)printf("Terminal type unknown\n");
  621. X        exit(1);
  622. X    }
  623. X    if(*profile == (char *) NULL) {
  624. X        *profile = NEWSTR(strlen(home)+strlen(PROFILE)+2);
  625. X        (void)sprintf(*profile, "%s/%s", home, PROFILE);
  626. X    }
  627. X    if(pager == (char *) NULL) {
  628. X        pager = NEWSTR(strlen(PAGER)+1);
  629. X        (void)strcpy(pager, PAGER);
  630. X    }
  631. X    if(shell == (char *) NULL) {
  632. X        shell = NEWSTR(strlen(SHELL)+1);
  633. X        (void)strcpy(shell, SHELL);
  634. X    }
  635. X    if(editor == (char *) NULL) {
  636. X        editor = NEWSTR(strlen(EDITOR)+1);
  637. X        (void)strcpy(editor, EDITOR);
  638. X    }
  639. X}
  640. X
  641. X
  642. Xstatic char argkeep[LEN];            /* storage for args from profile */
  643. X
  644. X/* --------------------
  645. X    Find mail directory, current-folder, context, default options.
  646. X-------------------- */
  647. Xvoid
  648. Xread_profile(pargc, pargv, profile, home)
  649. X    int *pargc;
  650. X    char **pargv, *profile, *home;
  651. X{
  652. X    FILE    *fp, *fopen();
  653. X    char    str[LEN], *ptr, iscontext[LEN], *index(), *next_token();
  654. X
  655. X    if((fp = fopen(profile, "r")) == (FILE *) NULL) {
  656. X        (void)printf("Profile: %s: cannot open.\n", profile);
  657. X        exit(1);
  658. X    }
  659. X    *iscontext = '\0';
  660. X    while(fgets(str, LEN, fp) != (char *) NULL) {
  661. X            /* get entries from profile */
  662. X        if(lstrncmp("context:", str, 8) == 0 && *(ptr=str+8) != '\0') {
  663. X            squash(str);
  664. X            (void)strcpy(iscontext, str+8);
  665. X        } else if(lstrncmp("vmail:", str, 6) == 0 && *(ptr=str+6) != '\0') {
  666. X            for( ; *ptr == ' ' || *ptr == '\t' ; ptr++)
  667. X                ;
  668. X            *index(ptr, '\n') = '\0';
  669. X            (void)strcpy(argkeep, ptr);
  670. X            for(ptr=argkeep ; *ptr != '\0' ; ) {
  671. X                pargv[(*pargc)++] = ptr;
  672. X                ptr = next_token(ptr);
  673. X            }
  674. X        } else if(lstrncmp("path:", str, 5) == 0 && *(ptr=str+5) != '\0') {
  675. X            squash(str);
  676. X            if(*ptr == '/') {        /* full pathname */
  677. X                mail_dir = NEWSTR(strlen(ptr)+1);
  678. X                (void)strcpy(mail_dir, ptr);
  679. X            } else {
  680. X                mail_dir = NEWSTR(strlen(home)+strlen(ptr)+1);
  681. X                (void)sprintf(mail_dir, "%s/%s", home, ptr);
  682. X            }
  683. X        } else if(lstrncmp("folder-protect:", str, 15) == 0 &&
  684. X                                                        *(str+15) != '\0') {
  685. X            squash(str);
  686. X            folder_protect = atoo(str+15);
  687. X        } else if(lstrncmp("current-folder:", str, 15) == 0 &&
  688. X                                                        *(str+15) != '\0') {
  689. X            squash(str);
  690. X            cur_folder = NEWSTR(strlen(str+15)+1);
  691. X            (void)strcpy(cur_folder, str);
  692. X        }
  693. X    }
  694. X    (void)fclose(fp);
  695. X    if(mail_dir == (char *) NULL) {
  696. X        mail_dir = NEWSTR(strlen(home)+strlen(MAILDIR)+2);
  697. X        (void)sprintf(mail_dir, "%s/%s", home, str+6);
  698. X    }
  699. X    if(access(mail_dir, R_OK | W_OK | X_OK)) {
  700. X        (void)printf("%s: no permissions.\n", mail_dir);
  701. X        exit(1);
  702. X    }
  703. X    if(*iscontext == '\0')
  704. X        (void)strcpy(iscontext, CONTEXT);
  705. X    context = NEWSTR(strlen(mail_dir)+strlen(iscontext)+2);
  706. X    (void)sprintf(context, "%s/%s", mail_dir, iscontext);
  707. X    if(access(context, R_OK | W_OK)) {
  708. X        (void)printf("%s: no permissions.\n", context);
  709. X        exit(1);
  710. X    }
  711. X    if(cur_folder == (char *) NULL)
  712. X        cur_folder = CURFOL;
  713. X}
  714. X
  715. X
  716. X/* --------------------
  717. X    Squash spaces, tabs, newlines out of given string.
  718. X-------------------- */
  719. Xvoid
  720. Xsquash(str)
  721. X    char    *str;
  722. X{
  723. X    int        i, j;
  724. X
  725. X    for(i=0, j=0 ; (str[j] = str[i]) != '\0' ; i++)
  726. X        if(str[j] != ' ' && str[j] != '\t' && str[j] != '\n')
  727. X            j++;
  728. X}
  729. X
  730. X
  731. X/* --------------------
  732. X    Mark folders as specified by setenv, command line.  At startup, default
  733. X    is for only active folder to be cur_folder.
  734. X-------------------- */
  735. Xvoid
  736. Xmark_valid_folders(argc, argv)
  737. X    int        argc;
  738. X    char    **argv;
  739. X{
  740. X    char    *name;
  741. X    folder    f;
  742. X
  743. X    name = cur_folder;
  744. X        /* find valid folders - mark all folders from argv as valid */
  745. X    for(; argc > 0 ; argc--, argv++)
  746. X        if(**argv == '+')                /* startup folder */
  747. X            name = (*argv) + 1;
  748. X        else if(**argv != '-') {        /* not a flag */
  749. X            GOTO_NAME(f, *argv);
  750. X            if(f == (folder) NULL)
  751. X                (void)printf("Warning: no such folder as %s\n", *argv);
  752. X            else
  753. X                f->valid = true;
  754. X        }
  755. X    GOTO_NAME(f, name);
  756. X    if(f == (folder) NULL) {
  757. X        (void)printf("%s does not exist\n", name);
  758. X        exit(1);
  759. X    }
  760. X    f->valid = true;
  761. X    curflr = f;
  762. X}
  763. X
  764. X
  765. X/* --------------------
  766. X    Reset terminal, clean up.
  767. X-------------------- */
  768. Xvoid
  769. Xto_normal()
  770. X{
  771. X    move(lines+FIRST-1, 0);
  772. X    refresh();
  773. X    no_control();
  774. X    (void)printf("\n");
  775. X}
  776. X
  777. X
  778. X/* --------------------
  779. X    Reset terminal.
  780. X-------------------- */
  781. Xvoid
  782. Xno_control()
  783. X{
  784. X    int x, y;
  785. X    char c;
  786. X
  787. X#ifdef STANDOUT_CLEANUP
  788. X    /*
  789. X     * The following code forces curses to issue a standend if it has
  790. X     * one pending.
  791. X     */
  792. X
  793. X    getyx(stdscr, y, x);
  794. X    c = inch() & 0x7f;
  795. X    if (c == 'a') {
  796. X        addch('b');
  797. X    }
  798. X    else {
  799. X        addch('a');
  800. X    }
  801. X    move(y, x);
  802. X    refresh();
  803. X    move(y, x);
  804. X    addch(c);
  805. X    move(y, x);
  806. X    refresh();
  807. X#endif
  808. X
  809. X    (void)ioctl(0, TIOCSETP, (caddr_t)&tty);
  810. X    (void)ioctl(0, TIOCSETP, (caddr_t)&chrs);
  811. X    (void)ioctl(0, TIOCSETP, (caddr_t)&lchrs);
  812. X}
  813. X
  814. X
  815. X/* --------------------
  816. X    Set terminal.
  817. X-------------------- */
  818. Xvoid
  819. Xto_control()
  820. X{
  821. X    (void)ioctl(0, TIOCSETP, (caddr_t)&t_tty);
  822. X    (void)ioctl(0, TIOCSETP, (caddr_t)&t_chrs);
  823. X    (void)ioctl(0, TIOCSETP, (caddr_t)&t_lchrs);
  824. X}
  825. X
  826. X
  827. X#define    mask(s)    (1 << ((s)-1))
  828. X
  829. X/* --------------------
  830. X    Trap for ^Z.
  831. X-------------------- */
  832. Xsig_type
  833. Xtstp()
  834. X{
  835. X    int        x, y;
  836. X
  837. X    getyx(curscr, y, x);
  838. X    to_normal();
  839. X    fix_mh();
  840. X
  841. X    (void)signal(SIGTSTP, SIG_DFL);
  842. X    (void)sigsetmask(sigblock(0) &~ mask(SIGTSTP));
  843. X    (void)kill(0, SIGTSTP);
  844. X    (void)sigblock(mask(SIGTSTP));
  845. X    (void)signal(SIGTSTP, tstp);
  846. X
  847. X    if(top_level) {
  848. X        to_control();
  849. X        touchwin(curscr);
  850. X        (void)wmove(curscr, y, x);
  851. X        (void)wrefresh(curscr);
  852. X    }
  853. X}
  854. X
  855. X
  856. X/* --------------------
  857. X    Trap for ^?.
  858. X-------------------- */
  859. X
  860. Xsig_type
  861. Xtint()
  862. X{
  863. X    touchwin(stdscr);
  864. X    addstatus("-- interrupt --", true);
  865. X    longjmp(env, 0);    /* jump to main */
  866. X}
  867. X
  868. X
  869. X/* --------------------
  870. X    Convert an ascii string to octal.
  871. X-------------------- */
  872. Xint
  873. Xatoo(str)
  874. X    char *str;
  875. X{
  876. X    int        i;
  877. X
  878. X    for(; *str < '0' && *str > '7' ; str++)
  879. X        ;
  880. X    for(i=0 ; *str >= '0' && *str <= '7' ; str++)
  881. X        i = i*8 + *str - '0';
  882. X    return(i);
  883. X}
  884. X
  885. X
  886. X/* --------------------
  887. X    Update MH environment - context and current mail item of current folder.
  888. X-------------------- */
  889. Xfix_mh()
  890. X{
  891. X    char str[LEN], buf[20];
  892. X
  893. X    update(context, "Current-Folder:", curflr->name, 15);
  894. X    (void)sprintf(str, "%s/%s/%s", mail_dir, curflr->name, SEQU);
  895. X    (void)sprintf(buf, "%d", curmail->number);
  896. X    update(str, "cur:", buf, 4);
  897. X}
  898. X
  899. X
  900. X/* --------------------
  901. X    Update file, replacing line beginning with match of len by "match new".
  902. X-------------------- */
  903. Xupdate(file, match, new, len)
  904. X    char    *file, *match, *new;
  905. X    int        len;
  906. X{
  907. X    FILE    *fp, *tmp, *fopen();
  908. X    bool    change = false;
  909. X    char    *mktemp(), *fgets();
  910. X    char    str[LEN], *name = mktemp("/tmp/vmail.XXXXXX");
  911. X
  912. X    if((fp = fopen(file, "r")) == (FILE *) NULL) {
  913. X        if((fp = fopen(file, "w+")) == (FILE *) NULL)
  914. X            (void)printf("Can't open %s for writing\n", file);
  915. X        else {
  916. X            (void)fprintf(fp, "%s %s\n", match, new);
  917. X            (void)fclose(fp);
  918. X        }
  919. X    } else {
  920. X        if((tmp = fopen(name, "w+")) == (FILE *) NULL)
  921. X            (void)printf("Can't open %s\n", file);
  922. X        else {
  923. X            while(fgets(str, LEN, fp) != (char *) NULL)
  924. X                if(lstrncmp(str, match, len) == 0) {
  925. X                    change = true;
  926. X                    (void)fprintf(tmp, "%s %s\n", match, new);
  927. X                } else
  928. X                    (void)fprintf(tmp, "%s", str);
  929. X            if(! change)
  930. X                (void)fprintf(tmp, "%s %s\n", match, new);
  931. X            (void)fclose(fp);
  932. X            (void)fclose(tmp);
  933. X            if((fp = fopen(file, "w+")) == (FILE *) NULL)
  934. X                (void)printf("Can't open %s for writing\n", file);
  935. X            else {
  936. X                tmp = fopen(name, "r");
  937. X                while(fgets(str, LEN, tmp) != (char *) NULL)
  938. X                    (void)fprintf(fp, "%s", str);
  939. X                (void)fclose(fp);
  940. X                (void)fclose(tmp);
  941. X                (void)unlink(name);
  942. X            }
  943. X        }
  944. X    }
  945. X}
  946. END_OF_init.c
  947. if test 11104 -ne `wc -c <init.c`; then
  948.     echo shar: \"init.c\" unpacked with wrong size!
  949. fi
  950. # end of overwriting check
  951. fi
  952. if test -f main.c -a "${1}" != "-c" ; then 
  953.   echo shar: Will not over-write existing file \"main.c\"
  954. else
  955. echo shar: Extracting \"main.c\" \(9902 characters\)
  956. sed "s/^X//" >main.c <<'END_OF_main.c'
  957. X#ifndef lint
  958. Xstatic char *RCS_main_c = "$Id: main.c,v 1.4 91/03/08 15:57:32 jamesp Exp $";
  959. X#endif
  960. X
  961. X/* --------------------
  962. X    vmail -- main.c
  963. X
  964. X    Definitions of global variables, main switch.
  965. X
  966. X    Copyright (C) J. Zobel, University of Melbourne, October 1987.
  967. X-------------------- */
  968. X
  969. X#include "defs.h"
  970. X
  971. Xfolder    folders = (folder) NULL, curflr, alternate = (folder) NULL;
  972. Xitem    curmail;
  973. Xchar     *user, *pager = (char *) NULL, *editor = (char *) NULL,
  974. X        *mail_dir = (char *) NULL, *shell = (char *) NULL, *context;
  975. Xbool    top_level = true, do_flush = true, comp_args = true, repl_args = true,
  976. X        forw_args = true, sort_args = true, burst_args = true,
  977. X        dist_args = true;
  978. Xint        lines, cols, y, folder_protect = FPROT;
  979. Xjmp_buf    env;
  980. X
  981. X#define HELP        (sizeof(help_scr) / sizeof(*help_scr))
  982. X
  983. Xchar *help_scr[] = {
  984. X"       .                Re-execute last command (if one of acdDefirR)",
  985. X"                                   (on repeat, r does not prompt for folder)",
  986. X"       /<exp>           Search forwards for title with <exp> (/ to repeat)",
  987. X"       ?<exp>           Search backwards for title with <exp> (? to repeat)",
  988. X"       <space>          Show current mail item",
  989. X"       [n]<return>      Go forward one (or n) active page(s) of mail items",
  990. X"       [n]<backspace>   Go back one (or n) active page(s) of mail items",
  991. X"       ^L               Refresh",
  992. X"       ^R               Refresh item listing, to match current mh folder",
  993. X"       !                Invoke shell",
  994. X"       |                Pipe current mail item into command",
  995. X"       ^                Go to first active page",
  996. X"       $                Go to last active page",
  997. X"       a                Answer current mail item (call to \"repl\")",
  998. X"       b                Burst current mail item as a digest",
  999. X"       c                Compose new mail item (call to \"comp\")",
  1000. X"       C                Go to folder chooser",
  1001. X"       [n]d             Delete current (or next inclusive n) mail item(s)",
  1002. X"       D                Delete current mail item, show next",
  1003. X"       e                Edit current mail item",
  1004. X"       f                Forward current mail item (call to \"forw\")",
  1005. X"       F                List all folders",
  1006. X"       g,G              Go to named (or alternate) folder",
  1007. X"       h                Show this page",
  1008. X"       [n]H             Go to top of page (or nth from top line)",
  1009. X"       i                Incorporate new mail (call to \"inc\")",
  1010. X"       [n]j             Move cursor down one (or n) line(s)",
  1011. X"       [n]k             Move cursor up one (or n) line(s)",
  1012. X"       [n]L             Go to bottom of page (or nth from bottom line)",
  1013. X"       M                Go to middle of page",
  1014. X"       [n]n             Go forward one (or n) folders, make new folder active",
  1015. X"       [n]p             Go back one (or n) folders, make new folder active",
  1016. X"       P                Print name of alternate folder",
  1017. X"       q                Exit from vmail",
  1018. X"       r,R              Refile item in named (or previous) folder",
  1019. X"       s                Save current item in named file",
  1020. X"       S                Sort mail items by date",
  1021. X"       t                Distribute mail item to new recipients (calls 'dist')",
  1022. X"       u                Undo most recent deletion (1 mail item only)",
  1023. X"       v                Make current folder inactive",
  1024. X"       z                Pack current folder"
  1025. X};
  1026. X
  1027. X
  1028. X#define USAGE    (void)printf( \
  1029. X"Usage: vmail [-inc] [-flush] [-comp] [-forw] [-ans] [+curfolder] folders ...\n"), \
  1030. X                exit(1)
  1031. X
  1032. Xmain(argc, argv)
  1033. X    int        argc;
  1034. X    char    *argv[];
  1035. X{
  1036. X    char    c, last = '\0', get_number(), flushin();
  1037. X    int        count = 1,        /* accumulate count to give to command */
  1038. X            pcount = 1;
  1039. X    bool    flag = false;    /* used to check whether to reset count */
  1040. X
  1041. X    argc--, argv++;
  1042. X
  1043. X    process_args(argc, argv);
  1044. X#ifndef VERSION
  1045. X#define VERSION    "(local version)"
  1046. X#endif
  1047. X    (void)printf("vmail %s -- reading mail headers\n", VERSION);
  1048. X    init(argc, argv);
  1049. X    (void)setjmp(env);        /* return point from interrupt */
  1050. X    c = flushin();
  1051. X    for(;;) {
  1052. X        while(c == '.')
  1053. X            if(last == '\0') {
  1054. X                beep();
  1055. X                c = flushin();
  1056. X            } else {
  1057. X                count = pcount;
  1058. X                c = last;
  1059. X            }
  1060. X        switch(c) {
  1061. X            case '|':    /* pipe mail to command */
  1062. X                do_pipe();
  1063. X                break;
  1064. X            case '!':    /* call shell */
  1065. X                call_shell();
  1066. X                break;
  1067. X            case '/':    /* search forwards */
  1068. X                search(true);
  1069. X                break;
  1070. X            case '?':    /* search backwards */
  1071. X                search(false);
  1072. X                break;
  1073. X            case '^':    /* first active page */
  1074. X                goto_first_page();
  1075. X                break;
  1076. X            case '$':    /* last active page */
  1077. X                goto_last_page();
  1078. X                break;
  1079. X            case '\n':    /* next folder */
  1080. X            case '\r':    /* next folder */
  1081. X                next_page(count, true);
  1082. X                break;
  1083. X            case ' ':    /* show current item */
  1084. X                show_mail();
  1085. X                break;
  1086. X            case DEL:    /* previous folder */
  1087. X            case '\b':    /* previous folder */
  1088. X                prev_page(count, true);
  1089. X                break;
  1090. X            case 'a':    /* answer - call to repl */
  1091. X                repl();
  1092. X                break;
  1093. X            case 'b':    /* burst current mail item */
  1094. X                burst_item();
  1095. X                break;
  1096. X            case 'c':    /* compose - fork of comp */
  1097. X                comp();
  1098. X                break;
  1099. X            case 'C':    /* go to folder chooser */
  1100. X                choose();
  1101. X                break;
  1102. X            case 'd':    /* delete item */
  1103. X                delete_item(count);
  1104. X                break;
  1105. X            case 'D':    /* delete item, show next */
  1106. X                (void)change_item(false);
  1107. X                show_mail();
  1108. X                break;
  1109. X            case 'e':    /* edit current mail item */
  1110. X                edit();
  1111. X                break;
  1112. X            case 'f':    /* forward - call to forw */
  1113. X                forw();
  1114. X                break;
  1115. X            case 'F':    /* list all folders */
  1116. X                list_folders();
  1117. X                break;
  1118. X            case 'g':    /* go to named folder */
  1119. X                goto_folder(true);
  1120. X                break;
  1121. X            case 'G':    /* go to last-named folder */
  1122. X                goto_folder(false);
  1123. X                break;
  1124. X            case 'h':    /* help */
  1125. X                help();
  1126. X                break;
  1127. X            case 'H':    /* go to top of page */
  1128. X                cursor_first(count);
  1129. X                break;
  1130. X            case 'i':    /* inc */
  1131. X                inc();
  1132. X                break;
  1133. X            case 'j':    /* cursor down */
  1134. X                cursor_down(count);
  1135. X                break;
  1136. X            case 'k':    /* cursor up */
  1137. X                cursor_up(count);
  1138. X                break;
  1139. X            case CTRL_L: /* redraw */
  1140. X                display_page();
  1141. X                break;
  1142. X            case 'L':    /* go to bottom of page */
  1143. X                cursor_last(count);
  1144. X                break;
  1145. X            case 'M':    /* go to middle of page */
  1146. X                cursor_middle();
  1147. X                break;
  1148. X            case 'n':    /* next folder - load if not there */
  1149. X                goto_next_folder(count);
  1150. X                break;
  1151. X            case 'p':    /* prev folder - load if not there */
  1152. X                goto_prev_folder(count);
  1153. X                break;
  1154. X            case 'P':    /* print name of last-named folder */
  1155. X                show_folder();
  1156. X                break;
  1157. X            case 'q':    /* quit */
  1158. X                to_normal();
  1159. X                fix_mh();
  1160. X                exit(0);
  1161. X                break;
  1162. X            case 'r':    /* move item to named folder */
  1163. X                move_item(true);
  1164. X                break;
  1165. X            case CTRL_R:    /* reread current folder */
  1166. X                refresh_folder();
  1167. X                break;
  1168. X            case 'R':    /* move item to previous folder */
  1169. X                move_item(false);
  1170. X                break;
  1171. X            case 's':    /* save item in named file */
  1172. X                save_item();
  1173. X                break;
  1174. X            case 'S':    /* sort current folder */
  1175. X                sort_folder();
  1176. X                break;
  1177. X            case 't':    /* dist a mail item to new people */
  1178. X                dist_item();
  1179. X                break;
  1180. X            case 'u':    /* undo */
  1181. X                undo();
  1182. X                break;
  1183. X            case 'v':    /* make folder inactive */
  1184. X                inactive();
  1185. X                break;
  1186. X            case 'z':    /* pack current folder */
  1187. X                pack_folder();
  1188. X                break;
  1189. X            case '0':    /* start of count */
  1190. X            case '1':
  1191. X            case '2':
  1192. X            case '3':
  1193. X            case '4':
  1194. X            case '5':
  1195. X            case '6':
  1196. X            case '7':
  1197. X            case '8':
  1198. X            case '9':
  1199. X                c = get_number(c, &count);
  1200. X                flag = true;
  1201. X                break;
  1202. X            default:
  1203. X                addstatus("command unknown -- `h' for help", true);
  1204. X                break;
  1205. X        }
  1206. X        switch(c) {
  1207. X                /* repeatable commands */
  1208. X            case 'r':    /* refile item in named folder */
  1209. X                last = 'R';
  1210. X                pcount = 1;
  1211. X                break;
  1212. X            case 'a':    /* reply - call to repl */
  1213. X            case 'c':    /* compose - fork of comp */
  1214. X            case 'd':    /* delete item */
  1215. X            case 'D':    /* delete item, show next */
  1216. X            case 'e':    /* edit current mail item */
  1217. X            case 'f':    /* forward - call to forw */
  1218. X            case 'i':    /* inc */
  1219. X            case 'R':    /* refile to previous folder */
  1220. X            case 't':    /* redistribute - call to dist */
  1221. X            case 'w':    /* write to file */
  1222. X                last = c;
  1223. X                pcount = count;
  1224. X                break;
  1225. X            default:
  1226. X                break;
  1227. X        }
  1228. X        if(!flag) {
  1229. X            c = flushin();
  1230. X            count = 1;
  1231. X        } else {
  1232. X            flag = false;
  1233. X        }
  1234. X    }
  1235. X}
  1236. X
  1237. X
  1238. X/* --------------------
  1239. X    Read a number from terminal.
  1240. X-------------------- */
  1241. Xchar
  1242. Xget_number(c, count)
  1243. X    char    c;
  1244. X    int        *count;
  1245. X{
  1246. X    *count = c - '0';
  1247. X    while((c = getchar()) >= '0' && c <= '9')
  1248. X        *count = *count * 10 + c - '0';
  1249. X    return(c);
  1250. X}
  1251. X
  1252. X
  1253. XWINDOW *helpwin = (WINDOW *) NULL;
  1254. X
  1255. X/* --------------------
  1256. X    Display help messages on help screen.
  1257. X-------------------- */
  1258. Xhelp()
  1259. X{
  1260. X    WINDOW    *newwin();
  1261. X    int        i, j;
  1262. X
  1263. X    if(helpwin == (WINDOW *) NULL)
  1264. X        helpwin = newwin(0, 0, 0, 0);
  1265. X    (void)wclear(helpwin);
  1266. X    for(j=i=0 ; i <= HELP ; i++, j++) {
  1267. X        if((i+2) % lines == 0) {
  1268. X            if(use_prompt(helpwin) == 'q')
  1269. X                break;
  1270. X            j=0;
  1271. X            (void)wclear(helpwin);
  1272. X        }
  1273. X        if(i >= HELP) {
  1274. X            (void)use_prompt(helpwin);
  1275. X            break;
  1276. X        }
  1277. X        mvwaddstr(helpwin, j+1, 0, help_scr[i]);
  1278. X    }
  1279. X    display_page();
  1280. X}
  1281. X
  1282. X
  1283. X/* --------------------
  1284. X    Process arguments, command-line or given in profile.
  1285. X-------------------- */
  1286. Xvoid
  1287. Xprocess_args(argc, argv)
  1288. X    int argc;
  1289. X    char *argv[];
  1290. X{
  1291. X    for( ; argc > 0 ; argc--, argv++)
  1292. X        if(!strcmp(argv[0], "-inc")) {    /* incorporate mail before starting */
  1293. X            if(!vfork()) {
  1294. X                execlp(INC, INC, 0);
  1295. X                (void)printf("Warning: can't execute %s\n", INC);
  1296. X                exit(0);
  1297. X            }
  1298. X            (void)wait((union wait *)0);
  1299. X            (void)printf("\n");
  1300. X        } else if(!strcmp(argv[0], "-flush"))    /* don't flush typeahead */
  1301. X            do_flush = false;
  1302. X        else if(!strcmp(argv[0], "-forw"))        /* no args to forw */
  1303. X            forw_args = false;
  1304. X        else if(!strcmp(argv[0], "-comp"))        /* no args to comp */
  1305. X            comp_args = false;
  1306. X        else if(!strcmp(argv[0], "-ans"))        /* no args to repl */
  1307. X            repl_args = false;
  1308. X        else if(!strcmp(argv[0], "-burst"))        /* no args to burst */
  1309. X            burst_args = false;
  1310. X        else if(!strcmp(argv[0], "-dist"))        /* no args to dist */
  1311. X            dist_args = false;
  1312. X        else if(!strcmp(argv[0], "-sort"))        /* no args to sort */
  1313. X            sort_args = false;
  1314. X        else if(*argv[0] == '-') {
  1315. X            (void)printf("%s: illegal option\n", argv[0]);
  1316. X            USAGE;
  1317. X        }
  1318. X}
  1319. END_OF_main.c
  1320. if test 9902 -ne `wc -c <main.c`; then
  1321.     echo shar: \"main.c\" unpacked with wrong size!
  1322. fi
  1323. # end of overwriting check
  1324. fi
  1325. if test -f move.c -a "${1}" != "-c" ; then 
  1326.   echo shar: Will not over-write existing file \"move.c\"
  1327. else
  1328. echo shar: Extracting \"move.c\" \(10258 characters\)
  1329. sed "s/^X//" >move.c <<'END_OF_move.c'
  1330. X#ifndef lint
  1331. Xstatic char *RCS_move_c = "$Id: move.c,v 1.3 91/03/08 15:57:57 jamesp Exp $";
  1332. X#endif
  1333. X
  1334. X/* --------------------
  1335. X    vmail -- move.c
  1336. X
  1337. X    Routines to delete or move a mail item from current folder.
  1338. X
  1339. X    Copyright (C) J. Zobel, University of Melbourne, October 1987.
  1340. X-------------------- */
  1341. X
  1342. X#include "defs.h"
  1343. X#include <errno.h>
  1344. X
  1345. Xstatic char prevfile[LEN] = "";
  1346. X
  1347. Xextern int errno;
  1348. X
  1349. X/* --------------------
  1350. X    Move current item to folder prevfile (get_name = false) or as read from
  1351. X    terminal (get_name = true).
  1352. X-------------------- */
  1353. Xvoid
  1354. Xmove_item(get_name)
  1355. X    bool    get_name;
  1356. X{
  1357. X    char    *s, str[LEN], str2[LEN];
  1358. X    folder    f, new_folder(), create_folder();
  1359. X    item    m;
  1360. X    bool    redraw;                        /* true if screen to be refreshed */
  1361. X    int        fdi, fdo, i = FIRST-1, num, N;
  1362. X
  1363. X        /* get name if required */
  1364. X    if(get_name || *prevfile == '\0') {
  1365. X        get_string("folder? ", str);
  1366. X        if(*str == '\0') {
  1367. X            addstatus("no name given for folder", true);
  1368. X            return;
  1369. X        }
  1370. X        (void)strcpy(prevfile, str);
  1371. X    } else
  1372. X        (void)strcpy(str, prevfile);
  1373. X        /* find first page of named folder */
  1374. X    (void)sprintf(str2, "refiling to %s ...", str);
  1375. X    addstatus(str2, false);
  1376. X    GOTO_NAME(f, str);
  1377. X    if(f == (folder) NULL) {    /* create folder */
  1378. X        f = create_folder(str);
  1379. X        if(f == (folder) NULL)
  1380. X            return;
  1381. X    } else {
  1382. X        if(f->name == curflr->name) {
  1383. X            addstatus("can't move item to current folder", true);
  1384. X            return;
  1385. X        }
  1386. X        if(f->valid) {        /* goto last mail item in folder */
  1387. X            LAST_OF_NAME(f);
  1388. X            for(i=FIRST, m=f->mail ; m->next != (item) NULL ; i++, m=m->next)
  1389. X                ;
  1390. X        }
  1391. X    }
  1392. X        /* remember current location of mail */
  1393. X    m = curmail;
  1394. X    num = curmail->number;
  1395. X    s = curflr->name;
  1396. X        /* delete item from current folder, update current folder & screen */
  1397. X    redraw = change_item(true);
  1398. X    if(f->valid)        /* update structures of mail items */
  1399. X        if(i > lines) {
  1400. X                /* create new folder record */
  1401. X            f = new_folder(f);
  1402. X            f->mail = f->last = m;
  1403. X            m->prev = m->next = (item) NULL;
  1404. X            N = f->prev->last->number;
  1405. X        } else {
  1406. X                /* insert at end of list of mail items */
  1407. X            m->prev = f->last; m->next = (item) NULL;
  1408. X            f->last->next = m;
  1409. X            f->last = m;
  1410. X            N = m->prev->number;
  1411. X        }
  1412. X    else
  1413. X        N = next_vacant(f);
  1414. X/* to avoid race between "send" or other process in background and vmail
  1415. X   foreground, compute next free slot, dont just use given value 
  1416. X*/
  1417. X    (void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
  1418. X        /* loop until unused file name found */
  1419. X    for(errno=0 ; (fdo = open(str2, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0
  1420. X                                            && errno == EEXIST ; errno=0) {
  1421. X        N = N + 1;
  1422. X        (void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
  1423. X    }
  1424. X    if(f->valid)
  1425. X        m->number = N;
  1426. X    (void)sprintf(str, "%s/%s/%d", mail_dir, s, num);
  1427. X    fdi = open(str, O_RDONLY);
  1428. X    while((i = read(fdi, str2, LEN)) > 0)    /* copy original to new */
  1429. X        (void)write(fdo, str2, i);
  1430. X    (void)close(fdi);
  1431. X    (void)close(fdo);
  1432. X    (void)unlink(str);                            /* remove original */
  1433. X    if(redraw)
  1434. X        display_page();
  1435. X    else {
  1436. X        add_page_header(str);
  1437. X        move(y, 0);
  1438. X        refresh();
  1439. X    }
  1440. X    addstatus("refiled", true);
  1441. X    if(curflr == (folder) NULL) {
  1442. X        to_normal();
  1443. X        exit(1);
  1444. X    }
  1445. X}
  1446. X
  1447. X
  1448. X/* --------------------
  1449. X    Delete count items.
  1450. X-------------------- */
  1451. Xvoid
  1452. Xdelete_item(count)
  1453. X    int        count;
  1454. X{
  1455. X    bool    redraw = false;
  1456. X    item    m;
  1457. X    char    str[LEN];
  1458. X
  1459. X    for( ; count > 0 ; count--) {
  1460. X        m = curmail->next;
  1461. X        redraw = change_item(false);
  1462. X        if(redraw || m != curmail) /* on new page, or last item deleted */
  1463. X            break;
  1464. X    }
  1465. X    if(redraw)
  1466. X        display_page();
  1467. X    else {
  1468. X        add_page_header(str);
  1469. X        move(y, 0);
  1470. X        refresh();
  1471. X    }
  1472. X}
  1473. X
  1474. X
  1475. X/* --------------------
  1476. X    Structure for deleted item.
  1477. X-------------------- */
  1478. Xstruct {
  1479. X    folder flr;
  1480. X    int number;
  1481. X} deleted = {(folder) NULL, 0};
  1482. X
  1483. X
  1484. X/* --------------------
  1485. X    Either delete (do_move = false) or prepare to move (do_move = true) item.
  1486. X    Delete item from current folder, update screen, find new current folder
  1487. X    if current folder has become empty.
  1488. X-------------------- */
  1489. Xbool
  1490. Xchange_item(do_move)
  1491. X    bool    do_move;
  1492. X{
  1493. X    item    tmp, m = curmail;
  1494. X    folder    F, p, f = curflr, pval, nval;
  1495. X    char    s1[LEN], s2[LEN];
  1496. X    bool    redraw, doexit = false;
  1497. X
  1498. X    if(curmail->next == (item) NULL && curmail->prev == (item) NULL) {
  1499. X            /* have last item in page */
  1500. X        redraw = true;
  1501. X        pval = curflr->prev; PREV_VALID(pval);
  1502. X        nval = curflr->next; NEXT_VALID(nval);
  1503. X        if(pval == (folder) NULL && nval == (folder) NULL) {
  1504. X                        /* no more active pages */
  1505. X            if(! do_move)
  1506. X                addstatus("Deleting last active mail item -- bye", true);
  1507. X            doexit = true;
  1508. X        } else {
  1509. X                /* update pages, pagenum */
  1510. X            for(p=curflr->prev ; p != (folder) NULL && p->name == curflr->name
  1511. X                                                                    ; p=p->prev)
  1512. X                p->pages -= 1;
  1513. X            for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name
  1514. X                                                                    ; p=p->next)
  1515. X                p->pages -= 1, p->pagenum -= 1;
  1516. X                /* find next active page, drop current page from list */
  1517. X            if(curflr->prev != (folder) NULL)
  1518. X                curflr->prev->next = curflr->next;
  1519. X            else
  1520. X                folders = curflr->next;
  1521. X            if(curflr->next != (folder) NULL)
  1522. X                curflr->next->prev = curflr->prev;
  1523. X            /*
  1524. X             * If the previous page is from the same folder,
  1525. X             * move to last item on that page.  Otherwise,
  1526. X             * move to first page of next folder if it is
  1527. X             * available, else move to first page of previous
  1528. X             * folder if it is available.
  1529. X             */
  1530. X            if (pval != (folder) NULL && pval->name == curflr->name) {
  1531. X                curflr = pval;
  1532. X                curmail = curflr->mail;
  1533. X                for ( ; curmail->next != (item) NULL; y++)
  1534. X                curmail = curmail->next;
  1535. X            }
  1536. X            else
  1537. X            {
  1538. X                curflr = (nval == (folder) NULL) ? pval : nval;
  1539. X                curmail = curflr->mail;
  1540. X            }
  1541. X        }
  1542. X    } else {
  1543. X        redraw = false;
  1544. X        deleteline();
  1545. X            /* move first item from next to current */
  1546. X        if(curflr->next != (folder) NULL && curflr->name == curflr->next->name)
  1547. X            show_title(s1, FIRST+lines-1, curflr->next->mail);
  1548. X        for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name ;
  1549. X                                                                    p=p->next) {
  1550. X            tmp = p->mail;
  1551. X            p->mail = tmp->next;
  1552. X            if(p->mail == (item) NULL) { /* remove folder from list */
  1553. X                p->prev->next = p->next;
  1554. X                if(p->next != (folder) NULL)
  1555. X                    p->next->prev = p->prev;
  1556. X                    /* update page counts */
  1557. X                for(F=p->prev ; F != (folder) NULL && F->name == p->name
  1558. X                                                                    ; F=F->prev)
  1559. X                    F->pages -= 1;
  1560. X            } else
  1561. X                p->mail->prev = (item) NULL;
  1562. X            p->prev->last->next = tmp;
  1563. X            tmp->prev = p->prev->last;
  1564. X            tmp->next = (item) NULL;
  1565. X            p->prev->last = tmp;
  1566. X        }
  1567. X            /* delete item from linked list of items */
  1568. X        if(m->prev == (item) NULL)
  1569. X            curflr->mail = m->next;
  1570. X        else
  1571. X            m->prev->next = m->next;
  1572. X        if(m->next == (item) NULL) {
  1573. X            curflr->last = m->prev;
  1574. X            curmail = m->prev;
  1575. X            y--;
  1576. X        } else {
  1577. X            m->next->prev = m->prev;
  1578. X            curmail = m->next;
  1579. X        }
  1580. X        move(y, 0);
  1581. X    }
  1582. X    if(! do_move) {
  1583. X        deleted.flr = f;
  1584. X        deleted.number = m->number;
  1585. X        (void)sprintf(s1, "%s/%s/%d", mail_dir, f->name, m->number);
  1586. X        (void)sprintf(s2, "%s/%s/#%d", mail_dir, f->name, m->number);
  1587. X        (void)rename(s1, s2);
  1588. X        if(doexit) {
  1589. X            to_normal();
  1590. X            exit(0);
  1591. X        }
  1592. X    }
  1593. X    return(redraw);
  1594. X}
  1595. X
  1596. X
  1597. X/* --------------------
  1598. X    Create folder of given name if user agrees, creating directory and
  1599. X    entry in linked list of folders.
  1600. X-------------------- */
  1601. Xfolder
  1602. Xcreate_folder(str)
  1603. X    char    *str;
  1604. X{
  1605. X    struct stat statbuf;
  1606. X    char    str2[LEN], c;
  1607. X    folder    fnew, p, f;
  1608. X
  1609. X    squash(str);
  1610. X    (void)sprintf(str2, "%s does not exist (or is empty) - create? ", str);
  1611. X    mvaddstr(STATUS, 0, str2); refresh();
  1612. X    c = getchar();
  1613. X    move(STATUS, 0); clrtoeol(); move(y, 0); refresh();
  1614. X    if(c != 'y')
  1615. X        return((folder) NULL);
  1616. X    for(p=(folder) NULL, f=folders ; f != (folder) NULL &&
  1617. X                            strcmp(str, f->name) > 0 ; p=f, f=f->next)
  1618. X        ;
  1619. X        /* create physical folder */
  1620. X    (void)sprintf(str2, "%s/%s", mail_dir, str);
  1621. X    if(stat(str2, &statbuf)) {        /* doesn't exist */
  1622. X        if(mkdir(str2, folder_protect)) {
  1623. X            addstatus("Cannot make folder", true);
  1624. X            return((folder) NULL);
  1625. X        }
  1626. X    } else
  1627. X        if(!(statbuf.st_mode & S_IREAD) || !(statbuf.st_mode & S_IWRITE)
  1628. X                                    || !(statbuf.st_mode & S_IEXEC)) {
  1629. X                addstatus("Cannot write in folder", true);
  1630. X                return((folder) NULL);
  1631. X        }
  1632. X            /* make a new folder record, insert it */
  1633. X    fnew = NEW(mail_folder);
  1634. X    fnew->name = NEWSTR(strlen(str)+1);
  1635. X    (void)strcpy(fnew->name, str);
  1636. X    fnew->mail = fnew->last = (item) NULL;
  1637. X    fnew->next = fnew->prev = (folder) NULL;
  1638. X    fnew->pages = fnew->pagenum = 1;
  1639. X    fnew->valid = false;
  1640. X    if(p == (folder) NULL) {
  1641. X        fnew->next = folders;
  1642. X        folders->prev = fnew;
  1643. X        folders = fnew;
  1644. X    } else {
  1645. X        p->next = fnew;
  1646. X        if(f != (folder) NULL)
  1647. X            f->prev = fnew;
  1648. X        fnew->prev = p;
  1649. X        fnew->next = f;
  1650. X    }
  1651. X    return(fnew);
  1652. X}
  1653. X
  1654. X
  1655. X/* --------------------
  1656. X    Crude undo.  Sophisticated undo rather too painful to code.
  1657. X-------------------- */
  1658. Xvoid
  1659. Xundo()
  1660. X{
  1661. X    folder    f = deleted.flr, p;
  1662. X    char    s1[LEN], s2[LEN];
  1663. X
  1664. X    if(f == (folder) NULL) {
  1665. X        addstatus("nothing to undo", true);
  1666. X        return;
  1667. X    } else {
  1668. X        addstatus("undoing ...", true);
  1669. X        deleted.flr = (folder) NULL;
  1670. X    }
  1671. X    (void)sprintf(s1, "%s/%s/#%d", mail_dir, f->name, deleted.number);
  1672. X    (void)sprintf(s2, "%s/%s/%d", mail_dir, f->name, deleted.number);
  1673. X    (void)rename(s1, s2);
  1674. X        /* find first page of folder */
  1675. X    p = f; FRST_OF_NAME(p);
  1676. X        /* find last page of folder */
  1677. X    LAST_OF_NAME(f);
  1678. X    curflr = p;
  1679. X    p->next = f->next;
  1680. X/* should free old folder/mail records */
  1681. X/*    p->valid = false; */
  1682. X    p->mail = p->last = (item) NULL;
  1683. X    p->pagenum = p->pages = 1;
  1684. X    if(p->next != (folder) NULL)
  1685. X        p->next->prev = p;
  1686. X    (void)find_mail(curflr, false);
  1687. X    curmail = curflr->mail;
  1688. X    y = FIRST;
  1689. X    display_page();
  1690. X}
  1691. X
  1692. X
  1693. X/* --------------------
  1694. X    Pack current folder.  Unsets "deleted" if last removed record was
  1695. X    on current folder.
  1696. X-------------------- */
  1697. Xvoid
  1698. Xpack_folder()
  1699. X{
  1700. X    folder    f = curflr;
  1701. X    item    m;
  1702. X    char    path[LEN], s1[LEN], s2[LEN];
  1703. X    bool    found;
  1704. X    int        newnum = 1;
  1705. X
  1706. X    addstatus("Packing folder ...", false);
  1707. X    FRST_OF_NAME(f);
  1708. X        /* unset undo if packing that folder */
  1709. X    if(deleted.flr != (folder) NULL && deleted.flr->name == curflr->name)
  1710. X        deleted.flr = (folder) NULL;
  1711. X    (void)sprintf(path, "%s/%s/", mail_dir, curflr->name);
  1712. X    for( ; f != (folder) NULL && f->name == curflr->name ; f=f->next)
  1713. X        for(m=f->mail ; m != (item) NULL ; m=m->next) {
  1714. X            for(found=false ; !found && newnum < m->number ; ) {
  1715. X                (void)sprintf(s1, "%s%d", path, newnum);
  1716. X                if(! access(s1, R_OK))
  1717. X                    newnum++;
  1718. X                else
  1719. X                    found = true;
  1720. X            }
  1721. X            if(found) {
  1722. X                (void)sprintf(s2, "%s%d", path, m->number);
  1723. X                (void)rename(s2, s1);
  1724. X                m->number = newnum;
  1725. X            }
  1726. X        }
  1727. X    display_page();
  1728. X}
  1729. END_OF_move.c
  1730. if test 10258 -ne `wc -c <move.c`; then
  1731.     echo shar: \"move.c\" unpacked with wrong size!
  1732. fi
  1733. # end of overwriting check
  1734. fi
  1735. if test -f vmail.1 -a "${1}" != "-c" ; then 
  1736.   echo shar: Will not over-write existing file \"vmail.1\"
  1737. else
  1738. echo shar: Extracting \"vmail.1\" \(10694 characters\)
  1739. sed "s/^X//" >vmail.1 <<'END_OF_vmail.1'
  1740. X.\" 
  1741. X.\" $Header: /mnts/metolius/home/jamesp/usr/src/vmail/RCS/vmail.1,v 1.3 91/03/08 15:58:57 jamesp Exp $
  1742. X.\" 
  1743. X.TH VMAIL 1 "30 September 1987"
  1744. X.UC Melb
  1745. X.SH NAME
  1746. Xvmail \- tty interface to MH
  1747. X.SH SYNOPSIS
  1748. X\fBvmail\fR
  1749. X[\-ans]
  1750. X[\-burst]
  1751. X[\-comp]
  1752. X[\-dist]
  1753. X[\-flush]
  1754. X[\-forw]
  1755. X[\-inc]
  1756. X[\-sort]
  1757. X[+cur_folder] folders ...
  1758. X.SH DESCRIPTION
  1759. X\fIvmail\fR is a tty interface to the MH mail system.
  1760. XIt combines most of the MH features into a single package, and performs
  1761. Xthe most frequently-used functions considerably faster than the
  1762. XMH equivalents.
  1763. XIn particular, a folder is only scanned once in a \fIvmail\fR
  1764. Xsession; the slow scan-show-rmm-scan cycle of MH is eliminated.
  1765. XAlso, \fIvmail\fR tends to be simpler for new users to learn than
  1766. Xthe MH system.
  1767. X.SH "STARTING UP"
  1768. X.LP
  1769. XWhen \fIvmail\fR is invoked, it loads mail headers for the folders
  1770. Xwhich will initially be active.
  1771. XThe default is for \fBinbox\fR (or the MH profile field Current-Folder)
  1772. Xto be the only active folder.
  1773. X(Other folders may be made active during the course of a session.)
  1774. XThere are a number of command-line flags.
  1775. X\fB\-inc\fR asks \fIvmail\fR to incorporate mail before loading any folders.
  1776. X\fB\-flush\fR instructs \fIvmail\fR not to flush typeahead.
  1777. X\fB\-comp\fR, \fB\-forw\fR, \fB\-ans\fR,
  1778. X\fB\-dist\fR, \fB\-burst\fR, and \fB\-sort\fR specify that \fIcomp\fR, \fIforw\fR,
  1779. X\fIrepl\fR (`answer'), \fIdist\fR, \fIburst\fR, and \fIsortm\fR
  1780. Xrespectively do not require that the user give
  1781. Xarguments; see the commands \fBc\fR, \fBf\fR, \fBa\fR,
  1782. X\fBt\fR, \fBb\fR, and \fBS\fR.
  1783. XArguments may also be set by the profile component \fBvmail\fR.
  1784. XTypical usage of \fIvmail\fR might be:
  1785. X.sp
  1786. X    vmail +priv inbox outbox
  1787. X.sp
  1788. Xto start up \fIvmail\fR with folders \fBpriv\fR, \fBinbox\fR, and
  1789. X\fBoutbox\fR active and with \fBpriv\fR as the current folder.
  1790. X\fIvmail\fR might then print
  1791. X.nf
  1792. X.sp
  1793. X\f(as    Vmail 9/87 -- reading mail headers
  1794. X            inbox: 122-279 (32 items)
  1795. X            outbox: 1-95 (19 items)
  1796. X            priv: 2-19 (5 items)\fR
  1797. X.sp
  1798. X.fi
  1799. Xas it loaded the named folders.
  1800. XWhen loading completed it would bring up the screen
  1801. Xrepresenting the mail items in the folder \fBpriv\fR.
  1802. X.nf
  1803. X.sp
  1804. X\f(as     priv (page 1 of 1)
  1805. X
  1806. X        2  17-06-86  fred@munnari    Just testing << Are you receiving
  1807. X        6   7-11-86  To: fred, nerk  A promise << The commitment: Dinn
  1808. X        7   9-05-87  bill            thanks for everything, but << wha
  1809. X       12  11-05-87 \-bill            Re: thanks for everything, but <<
  1810. X       19   9-05-87  To: bill        Re: thanks for everything, but <<\fR
  1811. X.sp
  1812. X.fi
  1813. X(Note that the dates in the example are in British format; a US installation
  1814. Xwould have the US form.)
  1815. XThe `\fB\-\fR' indicates that a reply has been sent to that piece of mail.
  1816. XText to the left of `\fB<<\fR' is the subject, other text is the
  1817. Xfirst part of the body.
  1818. XThe user could now move up and down between mail items with \fBk\fR and
  1819. X\fBj\fR, show the current mail item with \fB<space>\fR, delete the current
  1820. Xmail item with \fBd\fR, or forward or answer it with \fBf\fR or \fBa\fR.
  1821. X.LP
  1822. XIf the folder \fBpriv\fR contained  more mail items than could be
  1823. Xdisplayed on a screen, \fBpriv\fR would be broken into a number of pages.
  1824. X\fIvmail\fR has one or more pages for each active folder.
  1825. XThe user can move between pages, which are ordered alphabetically on
  1826. Xfolder name, by typing \fB<return>\fR and \fB<backspace>\fR 
  1827. X(forwards and backwards respectively).
  1828. X.SH "THE DETAILS"
  1829. X.LP
  1830. XFor those who like to mix use of MH and \fIvmail\fR, \fIvmail\fR
  1831. Xupdates the MH environment on \fBq\fR (quit), \fB!\fR (call shell)
  1832. Xand \fB^Z\fR (suspend).
  1833. XSpecifically, the fields `Current-Folder' in \fBcontext\fR and
  1834. X`cur' in \fBmh-profile\fR are updated to be the current folder and
  1835. Xcurrent mail item respectively.
  1836. XAlso, the \fB^R\fR command is useful for getting
  1837. Xvmail to sync up and recognize changes made by mh commands not
  1838. Xunder its control.
  1839. X.LP
  1840. XThe following points are relevant to all \fIvmail\fR commands.
  1841. XFirst, type-ahead is flushed (as in \fIrn\fR), so any commands
  1842. Xtyped ahead of time will be ignored.
  1843. XSecond, \fIvmail\fR always remembers the name of an ``alternate
  1844. Xfolder'', the last folder other than the current folder with which
  1845. Xthere has been an interaction (such as the folder to which an item
  1846. Xwas refiled, or the previous current folder).
  1847. XThis alternate folder is used by a number of commands.
  1848. XThird, some commands may be preceded by a count.
  1849. X.LP
  1850. XThe following is a complete list of \fIvmail\fR commands.
  1851. X.TP 10
  1852. X.B <space>
  1853. XShow current mail item (like \fIshow\fR).
  1854. X.TP 10
  1855. X.B <return>
  1856. XGo to next active page of mail headers (uses count).
  1857. X.TP 10
  1858. X.B <backspace>
  1859. XGo to previous active page of mail headers (uses count).
  1860. X.TP 10
  1861. X.B ^,$
  1862. XGo to the first (or last) active page of mail headers.
  1863. X.TP 10
  1864. X.B /,?
  1865. XSearch forwards (or backwards) through mail headers for the given
  1866. Xregular expression.
  1867. X\fB/<return>\fR will repeat search forwards, \fB?<return>\fR will repeat
  1868. Xthe search backwards.
  1869. XIt is not possible to backspace over \fB/\fR or \fB?\fR; use interrupt
  1870. Xinstead.
  1871. X.TP 10
  1872. X.B .
  1873. XRe-execute last command (if one of acdDefirR).
  1874. X(On repeat, \fBr\fR will not prompt for a folder name.)
  1875. X.TP 10
  1876. X.B ^L
  1877. XRefresh screen.
  1878. X.TP 10
  1879. X.B ^R
  1880. XRefresh list of items for this folder.
  1881. XThis rebuilds the \fIvmail\fR data structures.
  1882. X.B ^R
  1883. Xis useful for resyncing the item listing with changes made by
  1884. X\fIMH\fR commands not performed by vmail itself.
  1885. X.TP 10
  1886. X.B |
  1887. XPipe current mail item into command.
  1888. X.TP 10
  1889. X.B !
  1890. XInvoke your favourite shell (\fIcsh\fR by default).
  1891. X.TP 10
  1892. X.B a
  1893. XAnswer current mail item (call to \fIrepl\fR).
  1894. X\fIvmail\fR will ask for arguments unless \fB\-ans\fR has been set.
  1895. X\fIvmail\fR data structures won't be updated.
  1896. X.TP 10
  1897. X.B b
  1898. XBurst a mail item (call to \fIburst\fR).
  1899. XThis splits a digest or a message carrying several
  1900. Xforwarded messages into individual messages.
  1901. X\fIvmail\fR will ask for arguments unless \fB\-burst\fR has been set.
  1902. X\fIvmail\fR data structures will be updated.
  1903. X.TP 10
  1904. X.B c
  1905. XCompose new mail (call to \fIcomp\fR).
  1906. X\fIvmail\fR will ask for arguments unless \fB\-comp\fR has been set.
  1907. X\fIvmail\fR data structures won't be updated.
  1908. X.TP 10
  1909. X.B C
  1910. XInvoke the folder chooser.
  1911. XThis is a screen which permits users to select a current folder
  1912. Xby moving the cursor to a folder name with \fIvi\fR movement keys
  1913. Xand hitting \fB<space>\fR.
  1914. X.TP 10
  1915. X.B d
  1916. XDelete current mail item (uses count) (like \fIrmm\fR).
  1917. XActually, the mail item is moved from maildir/folder/num to maildir/folder/#num.
  1918. X\fIvi\fR users beware, \fBdd\fR deletes two items of mail.
  1919. X.TP 10
  1920. X.B D
  1921. XDelete current mail item, show next.
  1922. X.TP 10
  1923. X.B e
  1924. XEdit current mail item.
  1925. X.TP 10
  1926. X.B f
  1927. XForward current mail item (call to \fIforw\fR).
  1928. X\fIvmail\fR will ask for arguments unless \fB\-forw\fR has been set.
  1929. X\fIvmail\fR data structures won't be updated.
  1930. X.TP 10
  1931. X.B g,G
  1932. XGo to the named (or go to alternate) folder.
  1933. X.TP 10
  1934. X.B F
  1935. XShow all foldernames.
  1936. X.TP 10
  1937. X.B h
  1938. XDisplay the help screen.
  1939. X.TP 10
  1940. X.B H
  1941. XGo to top of page (or as offset by count).
  1942. X.TP 10
  1943. X.B i
  1944. XIncorporate mail (call to \fIinc\fR).
  1945. X\fIvmail\fR data structures are updated.
  1946. X.TP 10
  1947. X.B j
  1948. XMove cursor down (uses count).
  1949. XAt the bottom of the page, \fBj\fR will go to the top of the next page
  1950. Xof the current folder.
  1951. X.TP 10
  1952. X.B k
  1953. XMove cursor up (uses count).
  1954. XAt the top of the page, \fBk\fR will go to the bottom of the previous page
  1955. Xof the current folder.
  1956. X.TP 10
  1957. X.B L
  1958. XGo to bottom of page (or as offset by count).
  1959. X.TP 10
  1960. X.B M
  1961. XGo to middle of page.
  1962. X.TP 10
  1963. X.B n
  1964. XGo to the next folder, making it active if it is not so already (uses count).
  1965. X.TP 10
  1966. X.B p
  1967. XGo to the previous folder, making it active if it is not so
  1968. Xalready (uses count).
  1969. X.TP 10
  1970. X.B P
  1971. XPrint the name of the alternate folder.
  1972. X.TP 10
  1973. X.B q
  1974. XExit.
  1975. X.TP 10
  1976. X.B r
  1977. XRefile current item into the named folder.
  1978. X.TP 10
  1979. X.B R
  1980. XRefile current item into the last folder to which something was refiled.
  1981. X.TP 10
  1982. X.B s
  1983. XSave current mail item in the named file.
  1984. XMost filename expansions are not recognized, but `~/' and `~user/' are
  1985. Xreplaced by the appropriate paths.
  1986. X.TP 10
  1987. X.B S
  1988. XSort the current folder (call to \fIsortm\fR).
  1989. XThis sorts all the messages in the current folder
  1990. Xin order of the Date: lines.
  1991. X\fIvmail\fR will ask for arguments unless \fB\-sort\fR has been set.
  1992. X\fIvmail\fR data structures will be updated.
  1993. X.TP 10
  1994. X.B t
  1995. XDistribute an existing mail item to new recipients
  1996. X(call to \fIdist\fR).
  1997. X\fIvmail\fR will ask for arguments unless \fB\-dist\fR has been set.
  1998. X\fIvmail\fR data structures won't be updated.
  1999. X.TP 10
  2000. X.B u
  2001. XUndo most recent deletion.
  2002. X.TP 10
  2003. X.B v
  2004. XMake the current folder inactive.
  2005. X.TP 10
  2006. X.B z
  2007. XPack the current folder.
  2008. X.LP
  2009. XThe commands \fBa\fR, \fBc\fR, \fBt\fR and \fBf\fR update the physical folders,
  2010. Xbut the corresponding pages of mail headers in \fIvmail\fR are not updated.
  2011. X\fB^R\fR can be used to force the \fIvmail\fR
  2012. Xrepresentation of a folder to come up to date.
  2013. X.LP
  2014. X\fIvmail\fR recognizes the following environment variables.
  2015. XWhere they describe an executable, a full path name should be given.
  2016. X.TP 10
  2017. X.B SHELL
  2018. XSubshell invoked on `!'.
  2019. XDefault is \fI/bin/csh\fR.
  2020. X.TP 10
  2021. X.B PAGER
  2022. XDefault is \fI/usr/ucb/more\fR.
  2023. X.TP 10
  2024. X.B EDITOR
  2025. XUsed for editing stored mail.
  2026. XThe default is \fI/usr/ucb/vi\fR.
  2027. X.TP 10
  2028. X.B MH
  2029. XUsed to identify the MH profile.
  2030. XFrom the profile, \fIvmail\fR recognizes \fBPath\fR, \fBMsg-protect\fR
  2031. Xand \fBFolder-protect\fR.
  2032. XThe calls to MH utilities use the MH profile as appropriate.
  2033. XThe default is \fB~/.mh_profile\fR.
  2034. X.SH "PROFILE ENTRIES"
  2035. X.LP
  2036. XFolder-Protect (protection for new folders)
  2037. X.LP
  2038. XPath (of mail directory) 
  2039. X.LP
  2040. XCurrent-Folder (for startup folder)
  2041. X.LP
  2042. XVmail (list of arguments)
  2043. X.SH FILES
  2044. X.LP
  2045. X$HOME/.mh_profile
  2046. X.LP
  2047. X$HOME/Mail
  2048. X.LP
  2049. X$HOME/Mail/context
  2050. X.SH "SEE ALSO"
  2051. Xburst(1),
  2052. Xcomp(1),
  2053. Xdist(1),
  2054. Xforw(1),
  2055. Xinc(1),
  2056. Xrepl(1),
  2057. Xsortm(1).
  2058. X.SH HISTORY
  2059. X.LP
  2060. XOriginal program Copyright 1987 J. Zobel, jz@mulga.oz.au.
  2061. XPermission for redistribution and modifications were
  2062. Xpermitted,
  2063. Xproviding that the copyright notice remained intact.
  2064. X.LP
  2065. XBug fixes,
  2066. XSparc port,
  2067. Xburst,
  2068. Xdist,
  2069. Xresync commands added by James Perkins 1989-1991,
  2070. Xjamesp@metolius.wr.tek.com.
  2071. X.SH BUGS
  2072. X.LP
  2073. XCheck the alternate folder before using it unless absolutely sure
  2074. Xof its identity; a command may change it unexpectedly.
  2075. X.LP
  2076. XOnly a couple of formats of "Date:" lines are recognized; if the format is
  2077. Xdifferent, the date is replaced by a block of spaces.
  2078. X.LP
  2079. XStartup time is proportional to the number of items in the current folder.
  2080. XIt is therefore better to have a large number of folders each with fewer
  2081. Xmail items than a small number of large folders.
  2082. XMany first-time vmail users find that their inbox is large enough
  2083. X(> 400 items, say) that vmail takes a while to start up \- expect to
  2084. Xspend some time initially decluttering inbox and other large folders.
  2085. X.LP
  2086. XIf your inbox is empty at startup, vmail will
  2087. Ximmediately exit.
  2088. END_OF_vmail.1
  2089. if test 10694 -ne `wc -c <vmail.1`; then
  2090.     echo shar: \"vmail.1\" unpacked with wrong size!
  2091. fi
  2092. # end of overwriting check
  2093. fi
  2094. echo shar: End of archive 2 \(of 3\).
  2095. cp /dev/null ark2isdone
  2096. MISSING=""
  2097. for I in 1 2 3 ; do
  2098.     if test ! -f ark${I}isdone ; then
  2099.     MISSING="${MISSING} ${I}"
  2100.     fi
  2101. done
  2102. if test "${MISSING}" = "" ; then
  2103.     echo You have unpacked all 3 archives.
  2104.     rm -f ark[1-9]isdone
  2105. else
  2106.     echo You still need to unpack the following archives:
  2107.     echo "        " ${MISSING}
  2108. fi
  2109. ##  End of shell archive.
  2110. exit 0
  2111.